package br.edu.utfpr.sobjak.java.generics.ex1;

import java.util.Date;


/**
 * Classe gen�rica Par. Esta classe � capaz de manipular qualquer tipo T.
 * O "T" � substitu�do e tratado como uma classe ou interface existente real.
 *
 * @param <T>
 */
class Par<T> {
	T primeiro; // Utilizado como identificados de atributo
	T segundo;  // Utilizado como identificados de atributo

	/**
	 * No construtor da classe est� definido que um objeto "Par<T>", deve ser instanciado
	 * passando-se, como par�metro, dois objetos de tipo T.
	 *  
	 * @param a1
	 * @param a2
	 */
	Par(T a1, T a2) { 
		primeiro = a1;
		segundo = a2;
	}
}

/**
 * Classe gen�rica Par<T,U>. Esta classe � capaz de manipular qualquer tipo "T" e "U".
 * O "T" e o "U" s�o substitu�dos e tratados como uma classe ou interface existente real.
 *
 * @param <T>
 * @param <U>
 */
class ParDiferente<T, U> {
	T primeiro; // Utilizado como identificados de atributo
	U segundo;  // Utilizado como identificados de atributo

	/**
	 * No construtor da classe est� definido que um objeto "Par<T>", deve ser instanciado
	 * passando-se, como par�metro, dois objetos de tipo T.
	 *  
	 * @param a1
	 * @param a2
	 */
	public ParDiferente(T a1, U a2) { 
		primeiro = a1;
		segundo = a2;
	}
}




public class GenericoEx1 {
	public static void main(String[] args) {
		// Declara��o de um array de Strings
		String[] palavras = {"juca", "bom", "a", "pequeno","alface"};
		
		// Instanciando um Par<String>
		Par<String> mm = ArrayAlg.minmax(palavras);
		
		System.out.println(mm.primeiro);
		System.out.println(mm.segundo);
		
		
		
		Par<String> parString = new Par<String>("Lima", "Lim�o"); //OK! Os dois par�metros s�o do tipo String.
		Par<Date> parDatas = new Par<Date>(new Date(), new Date()); //OK! Os dois par�metors s�o do tipo java.util.Date
		//Par<String> parStringData = new Par<String>("Data", new Date()); //Fail! O segundo par�metro n�o � do tipo String.
		
		ParDiferente<String, Date> parStringData = new ParDiferente<>("Data", new Date()); //OK 
	}
}

/**
 * Classe Utilit�ria
 *
 */
class ArrayAlg {
	/**
	 * M�todo gen�rico: Retorna o elemento que est� na posi��o central do array.
	 * @param a
	 * @return
	 */
	public static <T> T getMeio(T[] a) {
		return a[a.length/2];
	}
	
	/**
	 * Este m�todo retorna um objeto "Par<T>" contendo o valor m�nimo e o m�ximo de um array de subtipos de Comparable.
	 * @param a
	 * @return
	 */
	public static <T extends Comparable<T>> Par<T> minmax(T[] a) {
		if( a == null || a.length == 0) return null;
		T min = a[0];
		T max = a[0];
		
		for (int i = 1; i < a.length; i++) {
			if(min.compareTo(a[i]) > 0) min = a[i];
			if(max.compareTo(a[i]) < 0) max = a[i];
		}
		
		return new Par<T>(min, max);
	}
}
